<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>系统监控与进程管理</title>
<!-- 引入 ECharts 库 -->
<script src="https://unpkg.com/echarts/dist/echarts.min.js"></script>
<style>
  body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f4f4f9;
  }
  .container {
    width: 90%;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    overflow: hidden;
  }
  .search-container {
    width: 100%;
    padding: 10px;
    text-align: center;
  }
  input[type="text"] {
    width: 80%;
    padding: 8px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }
  .table-container {
    width: 99%;
    overflow-y: auto;
    max-height: 400px;
    padding: 10px;
  }
  table {
    width: 100%;
    border-collapse: collapse;
  }
  th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
    font-size: 14px;
    cursor: pointer;
  }
  th {
    background-color: #f8f8f8;
    font-weight: bold;
  }
  tr:hover {
    background-color: #f5f5f5;
    cursor: pointer;
  }
  .selected-row {
    background-color: #cccccc !important;
  }
  .selected-cell {
    background-color: #bbdefb !important;
  }
  .end-button {
    background-color: #ff4d4d;
    color: white;
    border: none;
    padding: 5px 10px;
    border-radius: 4px;
    cursor: pointer;
  }
  .end-button:hover {
    background-color: #ff1a1a;
  }
  .charts-container {
    display: flex;
    justify-content: space-between;
    margin: 20px 0;
  }
  .chart {
    width: 48%;
    height: 400px;
  }
</style>
</head>
<body>
<div class="container">
  <div class="charts-container">
    <div id="cpuChart" class="chart"></div>
    <div id="memoryChart" class="chart"></div>
  </div>
  <div class="search-container">
    <input type="text" id="searchInput" placeholder="搜索进程...">
  </div>
  <div class="table-container">
    <h2 style="font-size: 16px; text-align: center; margin-bottom: 10px;">进程列表</h2>
    <table id="processTable">
      <thead>
        <tr>
          <th>序号</th>
          <th>pid</th>
          <th>名称</th>
          <th>用户</th>
          <th>总CPU时间</th>
          <th>内存使用（驻留集大小）</th>
          <th>虚拟内存大小</th>
          <th>状态</th>
          <th>开始时间</th>
          <th>线程数</th>
          <th>父进程ID</th>
          <th>优先级</th>
          <th>结束进程</th>
          <th>展示线程</th>
        </tr>
      </thead>
      <tbody id="processData">
      </tbody>
    </table>
  </div>
  <div class="threads-container" id="threadsContainer" style="display: none;">
    <h2 style="font-size: 16px; text-align: center; margin-bottom: 10px;">线程信息</h2>
    <table id="threadsTable">
      <thead>
        <tr>
          <th>总时间</th>
          <th>基本优先级</th>
          <th>实际优先级</th>
          <th>是否正常</th>
          <th>等待原因</th>
          <th>开始时间</th>
          <th>线程ID</th>
          <th>开始地址</th>
          <th>优先级提升功能</th>
          <th>内核时间</th>
          <th>状态</th>
          <th>用户时间</th>
          
        </tr>
      </thead>
      <tbody id="threadsData">
      </tbody>
    </table>
  </div>
</div>

<script>
let cpuChartInstance;
let memoryChartInstance;
let cpuLoadData = []; // 存储CPU负载数据的数组
const maxDataPoints = 100; // 最大数据点数量

async function fetchSystemInfo() {
  const response = await fetch('http://localhost:8080/api/system');
  const data = await response.json();
  console.log('Memory Total:', data.memoryTotal); // 打印总内存
  console.log('Memory Used:', data.memoryUsed); // 打印已用内存
  updateCharts(data);
}

function updateCharts(data) {
  // 更新 CPU 使用率图表
  if (!cpuChartInstance) {
    cpuChartInstance = echarts.init(document.getElementById('cpuChart'));
  }

  // 将新的CPU负载数据添加到数组中
  cpuLoadData.push(data.cpuLoad * 100);

  // 如果数据点数量超过最大值，则移除最早的数据点
  if (cpuLoadData.length > maxDataPoints) {
    cpuLoadData.shift();
  }

  // 创建x轴标签数组
  const xAxisData = cpuLoadData.map((_, index) => `Time ${index + 1}`);

  const cpuOption = {
    title: {
      text: 'CPU 负载'
    },
    tooltip: {},
    xAxis: {
      data: xAxisData
    },
    yAxis: {},
    series: [{
      name: '% Used',
      type: 'line',
      data: cpuLoadData
    }]
  };

  cpuChartInstance.setOption(cpuOption);

  // 初始化 内存使用情况图表
  if (!memoryChartInstance) {
    memoryChartInstance = echarts.init(document.getElementById('memoryChart'));
  }

  const memoryUsedGB = data.memoryUsed / (1024 * 1024 * 1024); // 将字节转换为GB
  const memoryFreeGB = (data.memoryTotal - data.memoryUsed) / (1024 * 1024 * 1024); // 将字节转换为GB
  const totalMemoryGB = (data.memoryTotal / (1024 * 1024 * 1024)).toFixed(2); // 计算总内存并转换为GB

  const memoryOption = {
    title: {
      text: `内存使用情况 (总内存: ${totalMemoryGB} GB)`
    },
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b} ({d}%)'
    },
    legend: {
      top: '5%',
      left: 'center',
      data: [`Used: ${memoryUsedGB.toFixed(2)} GB`, `Free: ${memoryFreeGB.toFixed(2)} GB`]
    },
    series: [
      {
        name: 'Memory',
        type: 'pie',
        radius: '50%',
        data: [
          { value: memoryUsedGB, name: `Used: ${memoryUsedGB.toFixed(2)} GB` },
          { value: memoryFreeGB, name: `Free: ${memoryFreeGB.toFixed(2)} GB` }
        ],
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        }
      }
    ]
  };

  memoryChartInstance.setOption(memoryOption);
}

// Fetch system info every 10 seconds
setInterval(fetchSystemInfo, 3000);

fetchSystemInfo(); // Initial load

const columnOrder = ["序号",
        "pid",
        "名称",
        "用户",
        "总CPU时间",
        "内存使用（驻留集大小）",
        "虚拟内存大小",
        "状态",
        "开始时间",
        "线程数",
        "父进程ID",
        "优先级"];
let currentSortColumn = null;
let sortAscending = true;
let lastFetchedProcesses = [];

async function fetchProcesses() {
  try {
    console.log('Fetching processes...'); // Debugging log
    const response = await fetch('http://localhost:8080/api/processes');
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    lastFetchedProcesses = await response.json();
    console.log('Fetched processes:', lastFetchedProcesses); // Debugging log
    updateDisplay();
  } catch (error) {
    console.error('Error fetching processes:', error);
    alert('获取进程列表时发生错误');
  }
}

function updateDisplay() {
  let processes = [...lastFetchedProcesses];
  const searchText = document.getElementById('searchInput').value.trim();
  if (searchText) {
    processes = filterProcesses(searchText, processes);
  }
  if (currentSortColumn) {
    processes = sortProcesses(processes, currentSortColumn, sortAscending);
  }
  displayProcesses(processes);
}

function formatMemory(bytes) {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

function formatCpuTime(ms) {
  const hours = Math.floor(ms / 3600000);
  ms %= 3600000;
  const minutes = Math.floor(ms / 60000);
  ms %= 60000;
  const seconds = Math.floor(ms / 1000);
  return `${hours}h ${minutes}m ${seconds}s`;
}

function formatDate(timestamp) {
  const date = new Date(timestamp);
  return date.toLocaleString();
}

function displayProcesses(processes) {
  const tableBody = document.getElementById('processData');
  tableBody.innerHTML = '';
  
  processes.forEach((process, index) => {
    const row = document.createElement('tr');
    
    columnOrder.forEach(key => {
      const cell = document.createElement('td');
      if (key === '序号') {
        cell.textContent = index + 1;
      } else if (key === '总CPU时间') {
        cell.textContent = formatCpuTime(process[key]);
      } else if (key === '内存使用（驻留集大小）' || key === '虚拟内存大小') {
        cell.textContent = formatMemory(process[key]);
      } else if (key === '开始时间') {
        cell.textContent = formatDate(process[key]);
      } else {
        cell.textContent = process[key]; // 使用空字符串作为默认值
      }
      cell.addEventListener('click', () => selectCell(cell, row));
      row.appendChild(cell);
    });

    // 添加结束按钮
    const endButtonCell = document.createElement('td');
    const endButton = document.createElement('button');
    endButton.className = 'end-button';
    endButton.textContent = '结束进程';
    endButton.addEventListener('click', () => endProcess(process.pid));
    endButtonCell.appendChild(endButton);
    row.appendChild(endButtonCell);

    // 添加显示线程按钮
    const showThreadsButtonCell = document.createElement('td');
    const showThreadsButton = document.createElement('button');
    showThreadsButton.className = 'end-button'; // 可以自定义样式类
    showThreadsButton.textContent = '显示线程';
    showThreadsButton.addEventListener('click', () => getthread(process.pid)); // 暂时与结束进程功能相同
    showThreadsButtonCell.appendChild(showThreadsButton);
    row.appendChild(showThreadsButtonCell);
    
    tableBody.appendChild(row);
  });
}

function selectCell(cell, row) {
  // Deselect all cells
  document.querySelectorAll('.selected-cell').forEach(c => c.classList.remove('selected-cell'));
  // Select the clicked cell
  cell.classList.add('selected-cell');
  
  // Select the row containing the clicked cell
  selectRow(row);
}

function selectRow(row) {
  // Deselect all rows
  document.querySelectorAll('.selected-row').forEach(r => r.classList.remove('selected-row'));
  // Select the clicked row
  row.classList.add('selected-row');
}

// Function to deselect all selected cells and rows
function deselectAll() {
  document.querySelectorAll('.selected-cell').forEach(c => c.classList.remove('selected-cell'));
  document.querySelectorAll('.selected-row').forEach(r => r.classList.remove('selected-row'));
}

// Add a click event listener to the document to deselect when clicking outside the table
document.addEventListener('click', (event) => {
  const tableContainer = document.querySelector('.table-container');
  if (!tableContainer.contains(event.target)) {
    deselectAll();
  }
});

// Function to sort processes by a given column
function sortProcesses(processes, column, ascending) {
  return processes.sort((a, b) => {
    if (a[column] < b[column]) {
      return ascending ? -1 : 1;
    }
    if (a[column] > b[column]) {
      return ascending ? 1 : -1;
    }
    return 0;
  });
}

// Add click event listeners to table headers
document.querySelectorAll('#processTable th').forEach((th, index) => {
  th.addEventListener('click', async () => {
    const column = th.textContent;
    if (column === currentSortColumn) {
      sortAscending = !sortAscending; // Toggle sort order
    } else {
      currentSortColumn = column;
      sortAscending = true; // Default to ascending order
    }
    updateDisplay();
  });
});

// Function to end a process
async function endProcess(pid) {
  try {
    console.log(`Ending process with PID: ${pid}`); // Debugging log
    const response = await fetch(`http://localhost:8080/api/processes/${pid}`, {
      method: 'DELETE'
    });
    console.log('Response status:', response.status); // Debugging log

    if (response.ok) {
      alert(`进程 ${pid} 已终止`);
      console.log('Fetching processes after ending process'); // Debugging log
      fetchProcesses(); // Refresh the process list
    } else {
      alert(`无法终止进程 ${pid}`);
      console.error('Failed to end process:', response.statusText); // Debugging log
    }
  } catch (error) {
    console.error('Error ending process:', error);
    alert('终止进程时发生错误');
  }
}

// Function to get a thread
// Function to get a thread
async function getthread(pid) {
  try {
    console.log(`Fetching threads for process with PID: ${pid}`); // Debugging log
    const response = await fetch(`http://localhost:8080/api/threads?pid=${pid}`);
    console.log('Response status:', response.status); // Debugging log

    if (response.ok) {
      const threads = await response.json();
      console.log('Threads:', threads); // Debugging log
      displayThreads(threads); // Display threads on the page
    } else {
      alert(`无法获取进程 ${pid} 的线程信息`);
      console.error('Failed to get threads:', response.statusText); // Debugging log
    }
  } catch (error) {
    console.error('Error getting threads:', error);
    alert('获取线程信息时发生错误');
  }
}
// Add a click event listener to the document to hide threads container when clicking outside
document.addEventListener('click', (event) => {
  const threadsContainer = document.getElementById('threadsContainer');
  if (threadsContainer.style.display === 'block' && !threadsContainer.contains(event.target)) {
    threadsContainer.style.display = 'none';
  }
});

function displayThreads(threads) {
  const threadsContainer = document.getElementById('threadsContainer');
  const threadsTableBody = document.getElementById('threadsData');
  
  // Clear previous threads data
  threadsTableBody.innerHTML = '';

  // Show threads container
  threadsContainer.style.display = 'block';

  threads.forEach(thread => {
    const row = document.createElement('tr');

    Object.keys(thread).forEach(key => {
      const cell = document.createElement('td');
      cell.textContent = thread[key];
      row.appendChild(cell);
    });

    threadsTableBody.appendChild(row);
  });
}


// Function to filter processes based on search input
function filterProcesses(searchText, processes) {
  const lowerCaseSearchText = searchText.toLowerCase();

  return processes.filter(process => {
    for (let key in process) {
      if (key === '序号') continue;
      let value = process[key];

      // 格式化特定字段
      if (key === '内存使用（驻留集大小）' || key === '虚拟内存大小') {
        value = formatMemory(value);
      } else if (key === '总CPU时间') {
        value = formatCpuTime(value);
      } else if (key === '开始时间') {
        value = formatDate(value);
      }

      if (value.toString().toLowerCase().includes(lowerCaseSearchText)) {
        if(lowerCaseSearchText.length>=3)
        {
            console.log(`Found match in ${key}: ${value}`);
        }
        
        return true;
        
      }
    }
    return false;
  });
}

// Add event listener to search input
document.getElementById('searchInput').addEventListener('input', updateDisplay);

// Fetch processes every 10 seconds
setInterval(fetchProcesses, 3000);

fetchProcesses(); // Initial load
</script>
</body>
</html>